#include <Ticker.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
#include <ESP8266WiFi.h>
#include "PubSubClient.h"
#include "Blwifi.h"
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <ESP8266httpUpdate.h>

const char* host = "SwitchUpdate";

const int relay_one = D5;

const int relay_two = D6;

ESP8266WebServer httpServer(80);

ESP8266HTTPUpdateServer httpUpdater;

const char* mqtt_server = "bemfa.com"; //默认，MQTT服务器
const int mqtt_server_port = 9501;      //默认，MQTT服务器
String ApiUrl = "https://api.bemfa.com";
int delaytime = 0;
String type = "2";
String uid = "";
String device = "";
String deviceIP = "";
String urlApi = "";
String fullUrl = "";
String upUrl = "http://bin.bemfa.com/b/1BcOGQ4MTVmN2NmNzcyNTgxYjhmZWMxODE2NTdlOTI3OWY=update.bin";

WiFiClientSecure httpClient;    //声明类 HTTPClient 的对象
WiFiClient espClient;
HTTPClient https;
PubSubClient clientPub(espClient);
void setup_wifi() {
  delay(1000);
  Serial.println();
  Serial.print("正在连接到：");
  Serial.print(wifiSettings.ssid);
  WiFi.begin(wifiSettings.ssid, wifiSettings.pswd);
  while (WiFi.status() != WL_CONNECTED) {
    delay(30);
    digitalWrite(LED_IO, LOW);
    delay(30);
    digitalWrite(LED_IO, HIGH);
    delay(30);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi 已连接");
  Serial.print("本机IP地址为：");
  Serial.println(WiFi.localIP());
  uid = wifiSettings.auth_key;
  device = wifiSettings.topic;
  deviceIP = WiFi.localIP().toString().c_str();
}
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("订阅的主题为：");
  Serial.println(topic);
  String msg = "";
  for (int i = 0; i < length; i++) {
    msg += (char)payload[i];
  }
  Serial.print("接收到的消息：");
  Serial.println(msg);
  if (msg == "on") {//如果接收字符on，亮灯
    Serial.print("接收到on命令......");
    turnOnLed();//开灯函数
  } else if (msg == "off") {//如果接收字符off，亮灯
    Serial.print("接收到off命令......");
    turnOffLed();//关灯函数
  } else if (msg == "ResetWifi") {
    Serial.print("接收到初始化命令系统正在初始化......");
    ResetWifi();
  } else if (msg == "getip") {
    clientPub.publish(device.c_str(), ("设备IP为：" + deviceIP).c_str());
  } else if (msg == "update") {
    Serial.print("接收到升级命令程序正在升级......");
    updateBin();
  }
  msg = "";
}

void reconnect() {
  // Loop until we're reconnected
  while (!clientPub.connected()) {
    Serial.print("尝试 MQTT 连接...");
    // Attempt to connect
    if (clientPub.connect(wifiSettings.auth_key)) {
      Serial.print("订阅的主题为：" );
      Serial.println(wifiSettings.topic);
      //订阅主题，如果需要订阅多个主题，可发送多条订阅指令client.subscribe(topic2);client.subscribe(topic3);
      clientPub.subscribe(wifiSettings.topic);
      getStatus();
      doHttpStick();
    } else {
      Serial.print("订阅的主题为：" );
      Serial.println(wifiSettings.topic);
      getStatus();
      Serial.print("连接失败: " );
      Serial.print(clientPub.state());
      Serial.println("正在重试......");
      // 等待 5 秒再重试
      delay(30);
      digitalWrite(LED_IO, LOW);
      delay(30);
      digitalWrite(LED_IO, HIGH);
      delay(30);
    }
  }
}
//打开灯泡
void turnOnLed() {
  Serial.println("设备已打开......");
  digitalWrite(LED_IO, LOW);
  digitalWrite(relay_one, LOW);
}
//关闭灯泡
void turnOffLed() {
  Serial.println("设备已关闭......");
  digitalWrite(LED_IO, HIGH);
  digitalWrite(relay_one, HIGH);
}

//******程序升级函数********//

void updateBin() {
  WiFiClient UpdateClient;
  t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl);
  switch (ret) {
    case HTTP_UPDATE_FAILED:      //当升级失败
      Serial.println("[update] Update failed.");
      break;
    case HTTP_UPDATE_NO_UPDATES:  //当无升级
      Serial.println("[update] Update no Update.");
      break;
    case HTTP_UPDATE_OK:         //当升级成功
      Serial.println("[update] Update ok.");
      break;
  }
}


//******微信消息推送函数********//
void doHttpStick() { //微信消息推送函数
  delay(5000);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  httpClient.setInsecure();
  urlApi = "/api/wechat/v1/weget.php?type=2&uid=" + uid + "&device=设备为："   +  device +  "&msg=" + "设备IP为：" + deviceIP;
  fullUrl = ApiUrl + urlApi;
  Serial.println("正在尝试向微信推送消息......");

  if (https.begin(httpClient, fullUrl)) {
    int httpCode = https.GET();
    Serial.println("服务器得到回应状态码: " + String(httpCode));
    if (httpCode > 0) {
      Serial.println(https.getString());
    } else {
      Serial.println("状态码异常: " + String(httpCode));
    }
    https.end();
  } else {
    Serial.println("服务器无法连接......");
  }
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  clientPub.publish(device.c_str(), ("设备IP为：" + deviceIP).c_str());
}

//=======================================================================

void getStatus() {
  delay(5000);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  httpClient.setInsecure();
  Serial.println("正在尝试获取最后一次状态......");
  urlApi = "/api/device/v1/data/3/get/?uid=" + uid + "&topic="  +  device;

  fullUrl = ApiUrl + urlApi;
  if (https.begin(httpClient, fullUrl)) {
    int httpCode = https.GET();
    Serial.println("服务器得到回应状态码: " + String(httpCode));
    if (httpCode > 0) {
      Serial.println(https.getString());
      String jsonStr = https.getString();
      String statusOnOff = "";
      String getok = "";
      String strCode = "";
      StaticJsonDocument<256> doc;
      DeserializationError error = deserializeJson(doc, jsonStr);

      if (error) {
        Serial.println("JSON解析失败!");
      } else {
        const char* data_0_msg = doc["data"][0]["msg"];
        const char* statusgetok = doc["status"]; // "getok"
        const char* code = doc["code"]; //
        strCode = code;
        if (strCode != "40220") {
          Serial.println("订阅的主题存在异常正在重新设置WIFI，请重新配置相关参数．．．．．．");
          ResetWifi(); //重新设置WIFI
          return;
        }
        statusOnOff = data_0_msg;
        Serial.println("本机IP为：" + WiFi.localIP().toString() + " ===获取到的状态为：" + statusOnOff);

        if (statusOnOff == "on") {//如果接收字符on，亮灯
          Serial.println("正在执行动作：" + statusOnOff);
          turnOnLed();//开灯函数
        } else if (statusOnOff == "off") {//如果接收字符off，亮灯
          Serial.println("正在执行动作：" + statusOnOff);
          turnOffLed();//关灯函数
        } else if (statusOnOff == "ResetWifi") {
          ResetWifi();
        }
      }


    } else {
      Serial.println("状态码异常: " + String(httpCode));
    }
    https.end();
  } else {
    Serial.println("服务器无法连接......");
  }
}

Ticker ticker;

void setup() {
  Serial.begin(115200);
  pinMode(LED_IO, OUTPUT); //设置引脚为输出模式
  pinMode(relay_one, OUTPUT); //设置引脚为输出模式
  pinMode(relay_two, OUTPUT); //设置引脚为输出模式
  Blwifi_InitWiFi();
  setup_wifi();           //设置wifi的函数，连接wifi
  for (int i = 0; i < 3; i++)
  {
    delay(500);
    digitalWrite(LED_IO, LOW);
    delay(500);
    digitalWrite(LED_IO, HIGH);
    delay(500);
  }

  clientPub.setServer(mqtt_server, mqtt_server_port);//设置mqtt服务器

  clientPub.setCallback(callback); //mqtt消息处理

  MDNS.begin(host);

  httpUpdater.setup(&httpServer);

  httpServer.begin();

  MDNS.addService("http", "tcp", 80);

}

void loop() {
  Blwifi_Loop();
  httpServer.handleClient();
  if (!clientPub.connected()) {
    reconnect();
  }
  clientPub.loop();
}
